package com.mrx.compose.weather.ui

import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.loadSvgPainter
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogWindow
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.WindowPosition
import androidx.compose.ui.window.rememberWindowState
import com.mrx.compose.weather.api.ApiHelper
import com.mrx.compose.weather.api.qweather.ApiConfig
import com.mrx.compose.weather.api.qweather.CityAPI
import com.mrx.compose.weather.api.qweather.CityAPI.Companion.cityInfo
import com.mrx.compose.weather.api.qweather.CityAPI.Companion.findDistrict
import com.mrx.compose.weather.api.qweather.WeatherAPI
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlin.coroutines.CoroutineContext

object WeatherWindow : CoroutineScope {

    private val iconCache = hashMapOf<Int, Painter>()

    private val weatherCache = hashMapOf<Int, WeatherAPI.WeatherResponse>()

    override val coroutineContext: CoroutineContext = Dispatchers.IO

    @Composable
    fun mainWindow(onClose: () -> Unit) {
        checkNotNull(ApiConfig.key)
        val windowState = rememberWindowState().apply {
            size = size
            position = WindowPosition(Alignment.Center)
        }
        Window(
            onCloseRequest = onClose,
            title = "天气预报",
            icon = loadPainter("qWeather".lowercase()),
            resizable = false,
            state = windowState
        ) {
            Row(modifier = Modifier.fillMaxSize().padding(start = 10.dp, top = 10.dp)) {
                val stateVertical = rememberScrollState(0)
                Column(modifier = Modifier.weight(1F).fillMaxWidth().verticalScroll(stateVertical)) {
                    app()
                }
                VerticalScrollbar(
                    modifier = Modifier.fillMaxHeight().width(10.dp),
                    adapter = rememberScrollbarAdapter(stateVertical)
                )
            }

        }
    }

    @Composable
    private fun app() {
        Column {
            val showAddDialog = remember { mutableStateOf(false) }
            val district = remember { mutableStateOf(listOf<CityAPI.CityInfoHolder>()) }
            Button(onClick = { showAddDialog.value = true }) { Text("添加城市") }
            addCityDialog(showAddDialog) {
                val array = district.value.toTypedArray()
                district.value = listOf(*array, it)
            }
            weatherCard(district.value)
        }
    }

    @Composable
    private fun weatherCard(cityInfoHolders: List<CityAPI.CityInfoHolder>) {
        for (holder in cityInfoHolders) {
            val weatherAPI = ApiHelper.getAPI<WeatherAPI>()
            val cityAPI = ApiHelper.getAPI<CityAPI>()
            val (pid) = holder.province!!
            val (cid) = holder.city!!
            val (did) = holder.district!!
            val weatherResponse = weatherCache.computeIfAbsent(did!!) {
                runBlocking {
                    val location = cityAPI.findDistrict(pid!!, cid!!).findDistrict(it)
                    weatherAPI.weatherNow(location.weather_id!!)
                }
            }
            weatherCard(holder, weatherResponse)
        }
    }

    @Composable
    private fun addCityDialog(show: MutableState<Boolean>, onClose: (CityAPI.CityInfoHolder) -> Unit) {
        DialogWindow(
            onCloseRequest = { show.value = false },
            visible = show.value,
            title = "添加城市",
            content = {
                Row(
                    verticalAlignment = Alignment.CenterVertically,
                    horizontalArrangement = Arrangement.SpaceAround,
                    modifier = Modifier.fillMaxWidth()
                ) {
                    val provinces = remember { mutableStateOf(cityInfo) }
                    val city = remember { mutableStateOf(listOf<CityAPI.CityInfo>()) }
                    val district = remember { mutableStateOf(listOf<CityAPI.CityInfo>()) }
                    val cityInfoHolder = remember { CityAPI.CityInfoHolder() }
                    fun clearCityDistrict() {
                        city.value = listOf()
                        district.value = listOf()
                    }
                    Row(Modifier.fillMaxWidth().weight(1F)) {
                        addCityRow(provinces.value) {
                            city.value = it.list
                            cityInfoHolder.province = it
                        }
                    }
                    Row(Modifier.fillMaxWidth().weight(1F)) {
                        addCityRow(city.value) {
                            district.value = it.list
                            cityInfoHolder.city = it
                        }
                    }
                    Row(Modifier.fillMaxWidth().weight(1F)) {
                        addCityRow(district.value) {
                            cityInfoHolder.district = it
                            onClose(cityInfoHolder)
                            clearCityDistrict()
                            show.value = false
                        }
                    }
                }
            })
    }

    @Composable
    private fun addCityRow(cityInfoList: List<CityAPI.CityInfo>, onItemClick: (CityAPI.CityInfo) -> Unit = {}) {
        val state = rememberScrollState(0)
        Row(modifier = Modifier.fillMaxWidth()) {
            Column(modifier = Modifier.fillMaxWidth().weight(1F).padding(10.dp).verticalScroll(state)) {
                for (cityInfo in cityInfoList) {
                    Text(cityInfo.name!!, Modifier.padding(bottom = 10.dp).clickable {
                        onItemClick(cityInfo)
                    })
                }
            }
            VerticalScrollbar(
                modifier = Modifier.fillMaxHeight().width(10.dp),
                adapter = rememberScrollbarAdapter(state)
            )
        }
    }

    @Composable
    private fun weatherCard(holder: CityAPI.CityInfoHolder, weatherResponse: WeatherAPI.WeatherResponse) {
        Row(
            verticalAlignment = Alignment.CenterVertically,
            modifier = Modifier.fillMaxWidth().padding(bottom = 10.dp)
        ) {
            loadWeatherIcon(weatherResponse.now!!)
            Text(
                "${holder.province!!.name} ${holder.city!!.name} ${holder.district!!.name}" +
                        " 天气情况: ${weatherResponse.toWeatherDescriptor()}",
                modifier = Modifier.fillMaxWidth().padding(start = 10.dp)
            )
        }
    }

    @Composable
    private fun loadWeatherIcon(now: WeatherAPI.WeatherResponse.Now) {
        val painter = loadPainter(now.icon!!.toString())
        Image(painter, now.text)
    }

    private fun loadPainter(icon: String) = iconCache.computeIfAbsent(icon.hashCode()) {
        val svgIcon = this::class.java.getResourceAsStream("/weather/icon/${icon}.svg")!!
        return@computeIfAbsent loadSvgPainter(svgIcon, Density(5F))
    }

    private fun Modifier.border(color: Color = Color.Red) = this.border(BorderStroke(1.dp, color))

    private fun Modifier.maxSizeBorder(color: Color = Color.Red) = this.fillMaxSize().border(color)

    private fun Modifier.maxWidthBroder(color: Color = Color.Red) = this.fillMaxWidth().border(color)

}